/**
 WhereIsMyMail Copyright (c) 2012 Artem Kuroptev

 This file is part of WhereIsMyMail. WhereIsMyMail is free software: you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the Free Software Foundation,
 either version 3 of the License, or (at your option) any later version.

 WhereIsMyMail is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with WhereIsMyMail. If not, see <http://www.gnu.org/licenses/>.
 */

package com.ucware.wimm.imaps;

import com.sun.mail.imap.IMAPFolder;

import javax.mail.*;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * $Id: Up.java 24 2014-11-25 21:06:27Z kuroptev@gmail.com $
 * @created 01.12.2012
 * @author Artem Kuroptev
 */
public class Up extends Fetch
{
    private static final Logger log = Logger.getLogger(Up.class.getName());
    protected static void log(Object s) {log.info(s.toString());}
    protected static void log(Throwable s) {log.log(Level.SEVERE, s.getLocalizedMessage(), s);}

    protected static final String MSG_GET_MESSAGES_BY_UID = "No search terms. Calling folder.getMessagesByUID({0}, {1}).. ";

    public static final String UID_VALIDITY = "com.ucware.wimm.imaps.Up.UIDValidity";
    public static final String UID_NEXT = "com.ucware.wimm.imaps.Up.UIDNext";
    public static final String STATUS_TIME = "com.ucware.wimm.imaps.Up.StatusTime";


    public static void main(String[] args) {
        try {
            setupLogManager();
            log("$Id: Up.java 24 2014-11-25 21:06:27Z kuroptev@gmail.com $");
            if(args.length < 2) {
                log("usage: java com.ucware.wimm.imaps.Up <imaps://user:password@host:port/path> <state-file>");
                return;
            }
            else {
                final String url = args[0];
                final String inPfn = args[1];
                final Properties mailProperties = new Properties(System.getProperties());

                final File inPropFile = new File(inPfn);

                // First run, init
                if(!inPropFile.exists()) {
                    final Properties state = initState(url, mailProperties);
                    log("Creating state file: " + inPfn);
                    writeProperties(inPfn, state);
                }
                // Normal run
                else {
                    log("Reading state file: " + inPfn);
                    final Properties state = readProperties(inPfn);

                    final long uidValidity = Long.parseLong(state.getProperty(UID_VALIDITY));
                    final long uidNext = Long.parseLong(state.getProperty(UID_NEXT));

                    final Properties newState = fetch(url, mailProperties, uidValidity, uidNext);

                    log("Writing state file: " + inPfn);
                    writeProperties(inPfn, newState);
                }
            }
        }
        catch (Exception e){
            log(e);
        }
    }

    public static Properties initState(final String url, final Properties mailProperties) throws MessagingException, ParseException, IOException
    {
        final Properties state = new Properties();

        // Connect
        final Session session = Session.getInstance(mailProperties, null);
        final URLName urlName = new URLName(url);
        final IMAPFolder folder = (IMAPFolder) session.getFolder(urlName);
        final Store store = folder.getStore();

        log("Folder open: " + folder.isOpen());
        log("Opening the folder.. ");
        folder.open(Folder.READ_ONLY);

        try {
            final Date date = new Date();
            log(STATUS_TIME + ": " + ATOM_DATETIME_FORMAT.format(date));
            state.setProperty(STATUS_TIME, ATOM_DATETIME_FORMAT.format(date));

            final long uidValidity = folder.getUIDValidity();
            log("folder.getUIDValidity(): " + uidValidity);
            state.setProperty(UID_VALIDITY, String.valueOf(uidValidity));

            final long uidNext = folder.getUIDNext();
            log("folder.getUIDNext(): " + uidNext);
            state.setProperty(UID_NEXT, String.valueOf(uidNext));
        }
        finally {
            folder.close(false);
            store.close();
        }
        return state;
    }



    public static Properties fetch(final String url, final Properties mailProperties, final long uidValidity, final long uidNext) throws MessagingException, ParseException, IOException
    {
        final Properties state = new Properties();

        // Connect
        final Session session = Session.getInstance(mailProperties, null);
        final URLName urlName = new URLName(url);
        final IMAPFolder folder = (IMAPFolder) session.getFolder(urlName);
        final Store store = folder.getStore();

        log("Folder open: " + folder.isOpen());
        log("Opening the folder.. ");
        folder.open(Folder.READ_ONLY);

        try {
            log("folder.getMessageCount(): " + folder.getMessageCount());

            final Date date = new Date();
            log(STATUS_TIME + ": " + ATOM_DATETIME_FORMAT.format(date));

            final long uidValidityNew = folder.getUIDValidity();
            log("folder.getUIDValidity(): " + uidValidityNew);

            if(uidValidity != uidValidityNew) {
                throw new IllegalStateException("Unexpected UIDValidity value: " + uidValidityNew);
            }

            final long uidNextNew = folder.getUIDNext();
            log("folder.getUIDNext(): " + uidNextNew);

            final Message[] messages; // Don't know if messages are in some order
            log(MessageFormat.format(MSG_GET_MESSAGES_BY_UID, uidNext, uidNextNew));
            messages = folder.getMessagesByUID(uidNext, uidNextNew);
            log("Light-weight Message objects retrieved: " + messages.length);

            // Retriving and saving
            exportMessages(messages);

            state.setProperty(STATUS_TIME, ATOM_DATETIME_FORMAT.format(date));
            state.setProperty(UID_VALIDITY, String.valueOf(uidValidityNew));
            state.setProperty(UID_NEXT, String.valueOf(uidNextNew));
        }
        finally {
            folder.close(false);
            store.close();
        }
        return state;
    }
}
